package gormInit

import (
	"fmt"
	"ginchat/utils/systemInit"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
	"io"
	"log"
	"os"
	"time"
)

// dsn后面K/V键值对参数
const (
	defaultCharSet = "utf8" 	// 客户端字符集
	defaultParseTime = true 	// 支持把数据库 datetime 和 date 类型转换为 golang 的 time.Time类型
	defaultloc = "Local"		// 使用系统本地时区
	defaultTimeOut = "10s" 		// 默认连接超时时间
	defaultReadTimeout = "0s"	// 读超时时间，0代表不限制
	defaultWriteTimeout = "0s"  // 写超时时间，0代表不限制
)

var db *gorm.DB

func Get() *gorm.DB{
	return db
}

func init() {
	initDb()
}

// initDb 初始化db 自定义gorm的格式
func initDb() {
	mysqlconfig := systemInit.Get().MysqlConfig
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=%t&loc=%s&timeout=%s",mysqlconfig.UserName,mysqlconfig.Password,mysqlconfig.Host,mysqlconfig.Port,mysqlconfig.DatabaseName,defaultCharSet,defaultParseTime,defaultloc,defaultTimeOut)

	var err error
	newLogger := initLogger()
	db, err = gorm.Open(mysql.Open(dsn),&gorm.Config{
		// 跳过默认事务
		SkipDefaultTransaction: false,
		// 命名策略：gorm采用的命名策略是，表名是蛇形复数，字段名是蛇形单数
		NamingStrategy: schema.NamingStrategy{
			TablePrefix:         "", // 表名前缀
			SingularTable:       false, // 复数表名
			NoLowerCase:         false,	// 开启小写转换
		},
		// 显示日志：gorm的默认日志是只打印错误和慢SQL
		Logger: *newLogger,
	})
	if err != nil{
		panic(any(err))
	}
}

// initLogger 自定义gorm日志的显示,打印SQL语句
func initLogger() *logger.Interface{
	//将日志输出到文件和终端里面
	err := os.MkdirAll("logs",os.ModePerm)
	if err != nil{
		panic(any(err))
	}
	file,err := os.OpenFile("logs/gormLog.log",os.O_CREATE|os.O_APPEND|os.O_RDWR,0666)
	if err != nil{
		panic(any(err))
	}
	writers := []io.Writer{
		file,
		os.Stdout,
	}

	newLogger := logger.New(
		log.New(io.MultiWriter(writers...),"\r\n",log.LstdFlags), // （日志输出的目标，前缀和日志包含的内容）
		logger.Config{
			SlowThreshold:             200*time.Millisecond,		 // 慢 SQL 阈值
			Colorful:                  true,	 // 使用彩色打印
			IgnoreRecordNotFoundError: false,	 // 忽略ErrRecordNotFound（记录未找到）错误
			ParameterizedQueries:      false,	 // 参数化查询(预防SQL注入攻击的攻击手法的防御方式)
			LogLevel:                  logger.Info,		 // 日志级别
		},
	)
	return &newLogger
}
